/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * Game.java
 *
 * Created on 2011-05-11, 07:16:34
 */
package jtmcraft.game;

import java.rmi.RemoteException;
import jtmcraft.game.communication.TextMessage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import jtmcraft.game.communication.client.ClientInterface;
import jtmcraft.game.communication.server.ServerInterface;
import jtmcraft.game.units.GameUnit;
import jtmcraft.game.units.GameUnitFactory.GameUnitType;
import jtmcraft.graphics.Renderer;

/**
 *
 * @author tom
 */
public class Game extends JPanel implements Runnable, ClientInterface {

    private Controller actionHandler;
    
    private Renderer render;
    private GameMap gameMap;
    boolean init = false;
    boolean loop = false;
    /** Creates new form Game */
    private GameMiniMap gameMiniMap;
    private GameButtonMenu gameButtonMenu;
    private GameUnit selectedUnit;
    
    ServerInterface serverInterface;
    int playerId;
    
    private ArrayList< TextMessage > textMessages = new ArrayList<TextMessage>();


    public Game() {
        initComponents();
    }

    public void InitGame(GameMiniMap gameMiniMap, 
                         GameButtonMenu gameButtonMenu,
                         int playerId,
                         ServerInterface serverInterface ) {

        this.gameMiniMap = gameMiniMap;
        this.gameButtonMenu = gameButtonMenu;
        this.serverInterface = serverInterface;
        this.playerId = playerId;


        
        actionHandler = new GameController( );
        actionHandler.setNextHandler( new CommunicationController() );

        /**
         * Start game, create player units
         */
        actionHandler.createMobileUnit( GameUnitType.warrior, 200, 100 );
        actionHandler.createMobileUnit( GameUnitType.warrior, 200, 180 );
        actionHandler.createBuildingUnit( GameUnitType.storehouse, 10, 10 );
        
        /**
         * This should go through RMI!
         */
        Player enemy = new Player();
        actionHandler.createEnemyPlayer( enemy );
        actionHandler.createEnemyMobileUnit( GameUnitType.warrior, 450, 450, 0 );

        gameMap = new GameMap(getGraphicsConfiguration());
        gameMap.Init();
        render = new Renderer(getWidth(), getHeight(), getGraphicsConfiguration(), gameMap);
        init = true;

        actionHandler.createNeutralGameUnit( GameUnitType.mine, 500, 100 );

        setIgnoreRepaint(true);

        for( GameUnit gu : actionHandler.getAllBuildingUnits() ) {
            gameMap.addBuilding( gu );
        }

        gameMap.invalidate();

        this.enableInputMethods(true);
        this.requestFocus();

        gameMiniMap.setIgnoreRepaint(true);
        gameMiniMap.enableInputMethods(false);
        gameMiniMap.Init(gameMap.getMaxWidth(), gameMap.getMaxHeight());

        gameButtonMenu.setIgnoreRepaint(true);
        gameButtonMenu.Init();

        /*
        long timeStamp = System.nanoTime() / 1000000;
        textMessages.add( new TextMessage("Pierwszy tekst", timeStamp + 2000) );
        textMessages.add( new TextMessage("Drugi tekst", timeStamp + 6000 ) );
        textMessages.add( new TextMessage( "Trzeci tekst", timeStamp + 10000 ) );
        textMessages.add( new TextMessage( "Czwarty tekst", timeStamp + 14000 ) );
         */
    }

    @Override
    public void addNotify() {
        super.addNotify();
        // new Thread(this).start();
    }

    public void updateSprites(long timeStamp) {
        for( GameUnit gameUnit : actionHandler.getPlayer().getMobileUnitList() ) {
            gameUnit.update( 100 );
            gameUnit.getSprite().process( timeStamp );
        }
        for ( Player enemy : actionHandler.getEnemies() ) {
            for( GameUnit gameUnit : enemy.getMobileUnitList() ) {
                gameUnit.update( 100 );
                gameUnit.getSprite().process( timeStamp );
            }
        }
    }

    public void drawGameUnit(List<GameUnit> gameUnits) {
        for (GameUnit gameUnit : gameUnits) {
            if (gameUnit.isInvisible()) {
                continue;
            }
            render.drawSprite(
                    gameUnit.getSprite(),
                    gameUnit.getX(),
                    gameUnit.getY(),
                    gameUnit.getWidth(),
                    gameUnit.getHeight(),
                    gameUnit.getPlayerColor(),
                    gameUnit.getDurability(),
                    gameUnit.getMaxDurability());

            if (gameUnit.isFocus() || gameUnit.isFlash()) {
                drawSelectedBox(gameUnit);
            }

            gameMiniMap.drawUnit(gameUnit, gameUnit.getPlayerColor());
        }

    }

    public void drawSelectedBox(GameUnit gameUnit) {
        render.drawSelectedBox(
                gameUnit.getSprite(),
                gameUnit.getX(),
                gameUnit.getY(),
                gameUnit.getWidth(),
                gameUnit.getHeight());

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                formMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                formMousePressed(evt);
            }
        });
        addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                formKeyPressed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void formMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseClicked
 
    }//GEN-LAST:event_formMouseClicked

    private void formKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyPressed

        if (evt.getKeyCode() == KeyEvent.VK_LEFT) {
            gameMap.scrollLeft();
        } else if (evt.getKeyCode() == KeyEvent.VK_RIGHT) {
            gameMap.scrollRight();
        } else if (evt.getKeyCode() == KeyEvent.VK_UP) {
            gameMap.scrollUp();
        } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) {
            gameMap.scrollDown();
        }
    }//GEN-LAST:event_formKeyPressed

    private void formMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMousePressed
       int xMouse = evt.getX() + gameMap.getxOffset();
        int yMouse = evt.getY() + gameMap.getyOffset();


        if (evt.getButton() == evt.BUTTON1) {
            selectedUnit = null;
            if ( actionHandler.getPlayer().getStorehouse().hitTest(xMouse, yMouse) ) {
                actionHandler.getPlayer().getStorehouse().select();
                selectedUnit = actionHandler.getPlayer().getStorehouse();
                gameButtonMenu.setCommandButtons( selectedUnit.getCommandButtons() );
            }
            else
            {
                actionHandler.getPlayer().getStorehouse().deselect();
                gameButtonMenu.setCommandButtons( null );

            }

            if (evt.isControlDown()) {
                for (GameUnit gameUnit : actionHandler.getPlayer().getGameUnits()) {
                    if (gameUnit.hitTest(xMouse, yMouse)) {
                        if (gameUnit.isFocus()) {
                            gameUnit.deselect();
                        } else {
                            gameUnit.select();
                            selectedUnit = gameUnit;
                        }
                    }
                }
            } else {
                for (GameUnit gameUnit : actionHandler.getPlayer().getGameUnits()) {
                    gameUnit.deselect();
                    if (gameUnit.hitTest(xMouse, yMouse)) {
                        gameUnit.select();
                        selectedUnit = gameUnit;
                    }
                }
            }
        }
        if (evt.getButton() == evt.BUTTON3) {
            // get selected units

            if (actionHandler.getPlayer().getStorehouse().hitTest(xMouse, yMouse)) {
                actionHandler.getPlayer().getStorehouse().flash();
                return;
            }

            ArrayList<GameUnit> selectedUnits = new ArrayList<GameUnit>();
            for (GameUnit gameUnit : actionHandler.getPlayer().getGameUnits()) {
                if (gameUnit.isFocus()) {
                    selectedUnits.add(gameUnit);
                }
            }
            // if there is any active unit
            if (selectedUnits.size() > 0) {
                // find out if clicked was provided on enemy unit
                GameUnit enemyTarget = null;
                for (Player enemy : actionHandler.getEnemies()) {
                    for (GameUnit enemyUnit : enemy.getGameUnits()) {
                        if (enemyUnit.hitTest(xMouse, yMouse)) {
                            enemyTarget = enemyUnit;
                            enemyUnit.flash();
                            break;
                        }
                    }
                }
                if (null != enemyTarget) {
                    for (GameUnit myUnit : selectedUnits) {
                        myUnit.pointEnemy(enemyTarget);
                    }
                    return;
                }
                GameUnit neutralTarget = null;
                // find out if there was neutral unit
                for (GameUnit neutralUnit : actionHandler.getNeutralGameUnits()) {
                    if (neutralUnit.hitTest(xMouse, yMouse)) {
                        neutralTarget = neutralUnit;
                        neutralUnit.flash();
                        break;
                    }
                }
                if (null != neutralTarget) {
                    for (GameUnit myUnit : selectedUnits) {
                        myUnit.pointNeutral(neutralTarget);
                    }
                    return;
                }
                for (GameUnit myUnit : selectedUnits) {
                    myUnit.point(xMouse, yMouse);
                }
            }
        }
    }//GEN-LAST:event_formMousePressed

    public void run() {

        System.out.println("isShowing: " + getParent().isShowing());
        System.out.flush();
        while (!getParent().isShowing()) {
            System.out.println("isShowing: " + getParent().isShowing());
            System.out.flush();
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException ex) {
                Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        // InitGame();


        System.out.println("start loop");

        int i = 1;
        while (true) {

            Graphics2D gd2 = (Graphics2D) getGraphics();
            if (gd2 != null) {
                long timeStamp = System.nanoTime() / 1000000;

                updateSprites(timeStamp);

                //odrysowywanie
                render.clearBackBuffer();
                gameMiniMap.clearBackBuffer();
                drawGameUnit(actionHandler.getPlayer().getMobileUnitList());
                for (Player enemy : actionHandler.getEnemies()) {
                    drawGameUnit(enemy.getMobileUnitList());
                }

                //rysujemy ramki dookola budynkow
                for (GameUnit building : gameMap.getBuildings()) {
                    gameMiniMap.drawUnit(building, building.getPlayerColor());
                    if (building.isFocus() || building.isFlash()) {
                        drawSelectedBox(building);
                    }
                }

                drawMenu();
                
                synchronized (this) {
                    updateTextMessage(timeStamp);

                    if (textMessages.size() > 0) {
                        render.drawMessage(textMessages);
                    }
                }
                render.update(gd2);
                gameMiniMap.update();
                gameButtonMenu.update();



                if (init && !loop) {
                    updateUI();
                }
                loop = true;

            }

            try {
                Thread.currentThread().sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void drawMenu()
    {

        gameButtonMenu.draw();

        /*

        if( selectedUnit == null || selectedUnit.getCommandButtons() == null ){
            gameButtonMenu.clearBackBuffer();
            return;
        }

        for( CommandButton commandButton : selectedUnit.getCommandButtons() )
        {
            gameButtonMenu.drawCommandButton(commandButton);
        }
         * &
         */

    }

    void updateTextMessage( long timestamp )
    {
        if( textMessages.size() < 1 ) return;

        ArrayList< TextMessage > newMessage = new ArrayList<TextMessage>();
        for( TextMessage message : textMessages )
        {
            if( message.getTimestamp() + 10000 > timestamp )
            {
                newMessage.add(message);
            }
        }
        textMessages.clear();
        textMessages = newMessage;
        
    }

    @Override
    protected void paintComponent(Graphics g) {

        if (!init) {
            super.paintComponent(g);
            g.setColor(Color.white);

        } else {
            if (loop) {
                render.update((Graphics2D) g);
            }
        }

    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables

    public void sendMessage( String msg )
    {
        try {
            serverInterface.sendMessage(playerId, msg);
        } catch (RemoteException ex) {
            Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    
    public void notifyTextMessage(String textMessage) {
        long timeStamp = System.nanoTime() / 1000000;
        TextMessage msg = new TextMessage(textMessage, timeStamp);
        synchronized (this) {
         textMessages.add(msg);
        }
    }

    public Controller getActionHandler() {
        return actionHandler;
    }

    public boolean isInit() {
        return init;
    }
    

}
